import { AssetField } from "./field/AssetField";
import { BooleanField } from "./field/BooleanField";
import { EnumField } from "./field/EnumField";
import { Field } from "./field/Field";
import { NumberField } from "./field/NumberField";
import { RangeField } from "./field/RangeField";
import { StringField } from "./field/StringField";
import { Vec2Field } from "./field/Vec2Field";
import { Vec3Field } from "./field/Vec3Field";
import { Vec4Field } from "./field/Vec4Field";

export type TypeProperty = {
    name: string,
    properties: AIPropertyDescriptor[]
}
export type AIPropertyDescriptor = {
    /** 如果设置了这个，则优先用这个来显示label */
    label?: string;
    /**属性名 */
    name: string,
    /**在这里写入，可以增加tip提示 */
    tip?: string,
    /**数据类型 */
    type?: "string" | "boolean" | "number" | 'Vector2' | "Vector3" | "Vector4",
    /** 说明此属性是引用一个资源 */
    isAsset?: boolean;
    /** 对资源类型的属性适用。多个资源类型用逗号分隔，例如“Image,Audio"。可用值参考editor/public/IAssetInfo.ts*/
    assetTypeFilter?: "Image" | "Audio" | "TypeScript" | "Atlas";
    /**默认值 */
    default?: any;
    /** 数值范围，等同于一次性设置min和max。 */
    range?: [number, number],
    /** 隐藏控制。
     * 可以用表达式
     * 字符串。例如"!data.a && !data.b"，表示属性a和属性b均为空时，隐藏这个属性。隐含的变量有两个，data为当前数据。
     */
    hidden?: boolean | string,
    /** 数字的最小值 */
    min?: number,
    /** 数字的最大值 */
    max?: number,
    /** 拖动方式改变数值时，每次数值改变的幅度。 */
    step?: number,
    /** 编辑这个类实例的控件 */
    inspector?: new () => IField,
    /** 提供数据源显示一个下拉框去改变属性的值 */
    enumSource?: EnumDescriptor;
    /** 当数值发生变化的时候的回调函数 */
    onChange?: (key: string, val: any, data: any) => void;
    onClick?: (e: gui.Event) => void;
}
export interface IField {
    create(o: AIPropertyDescriptor, data: any): gui.Widget;
}
export type EnumDescriptor = {
    name: string,
    value: any,
    extend?: EnumDescriptor,
    [index: string]: any,
}[] | any[] | string;

export class AIProperty {
    private static _init = false;
    static async init() {
        if (this._init) return;
        this._init = true;
        let arr = [
            "Asset",
            'Boolean',
            'Buttons',
            'Enum',
            'File',
            'Number',
            'Range',
            'String',
            'TextArea',
            'Tip',
            'Vec2',
            'Vec3',
            'Vec4',
            'ButtonList',
            'Button',
            'AIGenTTS',
        ];
        for (let i = arr.length - 1; i >= 0; i--) {
            await gui.UIPackage.resourceMgr.load('editorResources/AIUI/propertyItem/' + arr[i] + ".widget");
        }
        await gui.UIPackage.resourceMgr.load("editorResources/AIUI/AIProperty.widget");
    }
    static async create(property: TypeProperty, data: any) {
        if (!this._init) {
            await this.init();
        }
        let cont = gui.UIPackage.createWidgetSync("editorResources/AIUI/AIProperty.widget");
        cont.name = 'widget';
        let title = cont.getChild("title") as gui.TextField;
        title.text = property.name;


        let WindowCloseButton = cont.getChild('WindowCloseButton');

        WindowCloseButton.on('click', () => {
            cont.parent.parent.removeChild(cont.parent);
        });

        let arr = property.properties;
        let list = cont.getChild("List") as gui.List;
        for (let i = 0, len = arr.length; i < len; i++) {
            let itemProperty: any = null;
            let o = arr[i];


            if (null != o.inspector) {
                itemProperty = await new o.inspector().create(o, data);
            } else if (o.isAsset) {
                itemProperty = await new AssetField().create(o, data);
            } else if (o.enumSource) {
                itemProperty = await new EnumField().create(o, data);
            } else if (o.range) {
                itemProperty = await new RangeField().create(o, data);
            } else if ('number' == o.type) {
                itemProperty = await new NumberField().create(o, data);
            } else if ('string' == o.type) {
                itemProperty = await new StringField().create(o, data);
            } else if ("boolean" == o.type) {
                itemProperty = await new BooleanField().create(o, data);
            } else if ('Vector2' == o.type) {
                itemProperty = await new Vec2Field().create(o, data);
            } else if ('Vector3' == o.type) {
                itemProperty = await new Vec3Field().create(o, data);
            } else if ('Vector4' == o.type) {
                itemProperty = await new Vec4Field().create(o, data);
            }
            if (itemProperty) {
                list.addChild(itemProperty);
                itemProperty.width = list.width;
                itemProperty.addRelation(list, gui.RelationType.Width);
            }
        }
        return cont;
    }
}